package com.langyiquan.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.internal.org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.langyiquan.bo.WechatLoginBO;
import com.langyiquan.config.MiniProgramResource;
import com.langyiquan.exception.http.ParamException;
import com.langyiquan.pojo.Users;
import com.langyiquan.service.UserService;
import com.langyiquan.service.WechatService;
import com.langyiquan.utils.HttpUtils;
import com.langyiquan.utils.RedisOperator;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import springfox.documentation.spring.web.json.Json;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Service
public class WechatServiceImpl implements WechatService {

    final static Logger logger = LoggerFactory.getLogger(WechatServiceImpl.class);

    @Autowired
    private RedisOperator redisOperator;

    @Autowired
    private UserService userService;

    @Autowired
    private MiniProgramResource miniProgramResource;

    @Override
    public Users getUserInfo(WechatLoginBO wechatLoginBO) {
        Map<String, Object> userInfoMap = new HashMap<>();
        JSONObject sessionKeyOpenId = null;
        try {
            sessionKeyOpenId = getSessionKeyOrOpenId(wechatLoginBO.getCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 获取openId && sessionKey
        String openId = sessionKeyOpenId.getString("openid");
        String sessionKey = sessionKeyOpenId.getString("session_key");
        if(sessionKey == null){
            throw new ParamException(1017);
        }
        redisOperator.set("session_key",sessionKey,7000);

        Users insertOrUpdateUser = buildWechatUserAuthInfoDO(wechatLoginBO, sessionKey, openId);

        Users user = userService.getUserByOpenid(openId);
        if (user == null) {
            user = userService.createWechatUser(insertOrUpdateUser);
        } else {
            user = userService.updateWechatUser(user.getId(),insertOrUpdateUser);
        }

        return user;
    }

    private JSONObject getSessionKeyOrOpenId(String code) throws Exception {
        Map<String, String> requestUrlParam = new HashMap<>();
        // 小程序appId，自己补充
        requestUrlParam.put("appid", miniProgramResource.getAppId());

        // 小程序secret，自己补充
        requestUrlParam.put("secret", miniProgramResource.getAppSecret());
        // 小程序端返回的code
        requestUrlParam.put("js_code", code);
        // 默认参数
        requestUrlParam.put("grant_type", miniProgramResource.getGrantType());

        // 发送post请求读取调用微信接口获取openid用户唯一标识
        String result = HttpUtils.doPost(miniProgramResource.getRequestAccessTokenUrl(), requestUrlParam);
        return JSON.parseObject(result);
    }

    private Users buildWechatUserAuthInfoDO(WechatLoginBO wechatLoginBO, String sessionKey, String openId){
        Users users = new Users();
        users.setOpenid(openId);
        System.out.println(wechatLoginBO.getEncryptedData());
        JSONObject encryptedData = decryptUserInfo(wechatLoginBO.getEncryptedData(), sessionKey, wechatLoginBO.getIv());
        if (encryptedData != null){
            users.setUnionid(encryptedData.getString("unionId"));
            users.setNickname(encryptedData.getString("nickName"));
            users.setFace(encryptedData.getString("avatarUrl"));
            users.setSex(encryptedData.getInteger("gender"));
        }

        return users;
    }

    /**
     * 编码格式
     */
    private static final String ENCODING = "UTF-8";
    /**
     * 加密算法
     */
    public static final String KEY_ALGORITHM = "AES/CBC/PKCS5Padding";

    public static JSONObject decryptUserInfo(String encryptedData,String sessionKey,String iv) {
        try {
            byte[] data = Base64.decodeBase64(encryptedData);
            byte[] aseKey = Base64.decodeBase64(sessionKey);
            byte[] ivData = Base64.decodeBase64(iv);
            // 如果密钥不足16位，那么就补足
            int base = 16;
            if (aseKey.length % base != 0) {
                int groups = aseKey.length / base + (aseKey.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(aseKey, 0, temp, 0, aseKey.length);
                aseKey = temp;
            }
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            SecretKeySpec spec = new SecretKeySpec(aseKey, "AES");
            AlgorithmParameters parameters = generateIv(ivData);
            cipher.init(Cipher.DECRYPT_MODE, spec,parameters);
            byte[] result = cipher.doFinal(data);
            JSONObject jsonObject = JSONObject.parseObject(new String(result,ENCODING));
            return jsonObject;
        } catch (Exception e) {
            System.out.println("message:"+e.getMessage());
        }
        return null;
    }

    public static AlgorithmParameters generateIv(byte[] iv) throws Exception{
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }


}
